﻿using UnityEngine;
using System.Collections;
using MoreMountains.Tools;
using System;

namespace MoreMountains.CorgiEngine
{
    /// <summary>
    /// A class meant to be overridden that handles a character's ability. 
    /// </summary>
    [RequireComponent(typeof(Character))]
    public class CharacterAbility : MonoBehaviour
    {
        /// the sound fx to play when the ability starts
        public AudioClip AbilityStartSfx;
        /// the sound fx to play while the ability is running
        public AudioClip AbilityInProgressSfx;
        /// the sound fx to play when the ability stops
        public AudioClip AbilityStopSfx;

        /// if true, this ability can perform as usual, if not, it'll be ignored. You can use this to unlock abilities over time for example
        public bool AbilityPermitted = true;

        protected Character _character;
        protected CharacterHorizontalMovement _characterBasicMovement;
        protected CorgiController _controller;
        [SerializeField]
        protected InputManager _inputManager;
        protected CameraController _sceneCamera;
        protected Animator _animator;
        protected CharacterStates _state;
        protected SpriteRenderer _spriteRenderer;
        protected StateMachine<CharacterStates.MovementStates> _movement;
        protected StateMachine<CharacterStates.CharacterConditions> _condition;
        protected AudioSource _abilityInProgressSfx;

        //  custom
        protected SaveAblityEvent _saveAblity;

        /// This method is only used to display a helpbox text at the beginning of the ability's inspector
        public virtual string HelpBoxText() { return ""; }

        /// <summary>
        /// On Start(), we call the ability's intialization
        /// </summary>
        protected virtual void Start()
        {
            Initialization();
        }

        /// <summary>
        /// Gets and stores components for further use
        /// </summary>
        protected virtual void Initialization()
        {
            _character = GetComponent<Character>();
            _controller = GetComponent<CorgiController>();
            _characterBasicMovement = GetComponent<CharacterHorizontalMovement>();
            _spriteRenderer = GetComponent<SpriteRenderer>();
            _animator = _character._animator;
            _sceneCamera = _character.SceneCamera;
            _inputManager = _character.LinkedInputManager;
            _state = _character.CharacterState;
            _movement = _character.MovementState;
            _condition = _character.ConditionState;
            if (_animator != null)
            {
                InitializeAnimatorParameters();
            }

            _saveAblity = GetComponent<SaveAblityEvent>();
        }

        /// <summary>
        /// Adds required animator parameters to the animator parameters list if they exist
        /// </summary>
        protected virtual void InitializeAnimatorParameters()
        {

        }

        /// <summary>
        /// Internal method to check if an input manager is present or not
        /// </summary>
        protected virtual void InternalHandleInput()
        {
            if (_inputManager == null) { return; }
            if (CheckHandleInput() == true && _inputManager.EnableBtnDownEvent == true)
            {
                HandleInput();
            }
            else if (CheckSavedable() == true)
            {
                _saveAblity.SetSavedEvent(HandleInput);

                //Debug.Log("你存的是   " + this.GetType());
            }
        }

        //  通过这里的检查后才能进行HandleInput
        protected virtual bool CheckHandleInput()
        {
            return true;
        }
        /// <summary>
        /// 通过这里的检查后才能进行保存,默认返回  CheckHandleInput()
        /// </summary>
        /// <returns></returns>
        protected virtual bool CheckSavedable()
        {
            return CheckHandleInput();
        }
        /// <summary>
        /// Called at the very start of the ability's cycle, and intended to be overridden, looks for input and calls methods if conditions are met
        /// </summary>
        protected virtual void HandleInput()
        {
            //  这是处理动作的主要方法
        }
        /// <summary>
        /// The first of the 3 passes you can have in your ability. Think of it as EarlyUpdate() if it existed
        /// </summary>
        public virtual void EarlyProcessAbility()
        {
            InternalHandleInput();
        }

        /// <summary>
        /// The second of the 3 passes you can have in your ability. Think of it as Update()
        /// </summary>
        public virtual void ProcessAbility()
        {

        }

        /// <summary>
        /// The last of the 3 passes you can have in your ability. Think of it as LateUpdate()
        /// </summary>
        public virtual void LateProcessAbility()
        {

        }

        /// <summary>
        /// Override this to send parameters to the character's animator. This is called once per cycle, by the Character class, after Early, normal and Late process().
        /// </summary>
        public virtual void UpdateAnimator()
        {

        }

        /// <summary>
        /// Changes the status of the ability's permission
        /// </summary>
        /// <param name="abilityPermitted">If set to <c>true</c> ability permitted.</param>
        public virtual void PermitAbility(bool abilityPermitted)
        {
            AbilityPermitted = abilityPermitted;
        }

        /// <summary>
        /// Override this to specify what should happen in this ability when the character flips
        /// </summary>
        public virtual void Flip()
        {

        }

        /// <summary>
        /// Override this to reset this ability's parameters. It'll be automatically called when the character gets killed, in anticipation for its respawn.
        /// </summary>
        public virtual void Reset()
        {

        }

        /// <summary>
        /// Plays the ability start sound effect
        /// </summary>
        protected virtual void PlayAbilityStartSfx()
        {
            if (AbilityStartSfx != null)
            {
                //SoundManager.Instance.PlaySound(AbilityStartSfx, transform.position);
            }
        }

        /// <summary>
        /// Plays the ability used sound effect
        /// </summary>
        protected virtual void PlayAbilityUsedSfx()
        {
            if (AbilityInProgressSfx != null)
            {
                if (_abilityInProgressSfx == null)
                {
                    //_abilityInProgressSfx = SoundManager.Instance.PlaySound(AbilityInProgressSfx, transform.position, true);
                }
            }
        }

        /// <summary>
        /// Stops the ability used sound effect
        /// </summary>
        protected virtual void StopAbilityUsedSfx()
        {
            if (AbilityInProgressSfx != null)
            {
                //SoundManager.Instance.StopLoopingSound(_abilityInProgressSfx);
                _abilityInProgressSfx = null;
            }
        }

        /// <summary>
        /// Plays the ability stop sound effect
        /// </summary>
        protected virtual void PlayAbilityStopSfx()
        {
            if (AbilityStopSfx != null)
            {
                //SoundManager.Instance.PlaySound(AbilityStopSfx, transform.position);
            }
        }

        /// <summary>
        /// Registers a new animator parameter to the list
        /// </summary>
        /// <param name="parameterName">Parameter name.</param>
        /// <param name="parameterType">Parameter type.</param>
        protected virtual void RegisterAnimatorParameter(string parameterName, AnimatorControllerParameterType parameterType)
        {
            bool hasParams = false;

            if (parameterName != null && parameterName != "")
            {
                AnimatorControllerParameter[] parameters = _animator.parameters;
                foreach (AnimatorControllerParameter currParam in parameters)
                {
                    if (currParam.type == parameterType && currParam.name == parameterName)
                    {
                        hasParams = true;
                        break;
                    }
                }
            }
            if (hasParams)
            {
                _character._animatorParameters.Add(parameterName);
            }
        }


        protected virtual void ControlInput(bool enable)
        {
            _inputManager.EnableBtnDownEvent = enable;
            if (enable == true)
                _character.HorizontalMoveControl = Character.HorizontalControlType.All;
            else
                _character.HorizontalMoveControl = Character.HorizontalControlType.CannotControl;

            if (enable == false)
                _saveAblity.StartRecord();      //  关闭模式下  才开始记录
            else if (enable == true)
            {
                _saveAblity.CloseRecord();
                _saveAblity.InvokeSavedEvent();     //  此方法也许在子类手动调用最合适 
            }
        }

        protected virtual DamageInfo CalcDamageInfo()
        {
            throw new Exception();
        }
    }
}